# -*- coding: utf-8 -*-
'''
@summary: Módulo DataManager.py comporta todas as funçoes para consulta
na base de dados e chamadas de gráficos

@requires: ExportFile.py

@development environment:
Maquina Virtual com Debian7.1
Python 2.7
wxGlade

@author: Adriano Leal - 11951, Gonçalo Ferreira - 11958
@version: 2.4
@date: 04/12/2013
'''

import sqlite3

from pylab import *
import ExportFile
import DataBase


class Datamanager(object):
    conexaoObj = None

    def cursor(self):
        return self.conexao().cursor()

    def conexao(self):
        if self.conexaoObj is None:
            #db = create_engine('sqlite:///cna.db', encoding='latin1', echo=True)
            self.conexaoObj = sqlite3.connect("cna.db")
        return self.conexaoObj

    """
    Contém todas as funções que geram as estatisticas e gráficos.
    """
    #Lista de arrays necessários para guardar a informaçao advinda das
    #consultas à base de dados
    geral_code = []
    nome_inst = []
    codigo_instituicao = []
    colocados_p_inst = []
    nome_distritos = []
    colocados_p_inst = []
    colocados_p_dist = []
    colocados_p_dist1 = []
    vagas_p_inst = []
    vagas_p_dist = []
    vagas_p_dist_init = []
    porcentagem = []
    nome_institui = []
    porcentagem_valor_zip = []
    permilagem = []
    pormilagem_valor_zip = []
    colocados_dist = []
    nome_instituicao = []


    def limpa_lista(self):
        '''
        Funçao que limpa as listas evitando a sobreposiçao de graficos
        '''
        del self.geral_code[:]
        del self.nome_inst[:]
        del self.codigo_instituicao[:]
        del self.colocados_p_inst[:]
        del self.nome_distritos[:]
        del self.colocados_p_inst[:]
        del self.colocados_p_dist[:]
        del self.colocados_p_dist1[:]
        del self.vagas_p_inst[:]
        del self.vagas_p_dist[:]
        del self.vagas_p_dist_init[:]
        del self.porcentagem[:]
        del self.nome_institui[:]
        del self.porcentagem_valor_zip[:]
        del self.permilagem[:]
        del self.pormilagem_valor_zip[:]
        del self.colocados_dist[:]
        del self.nome_instituicao[:]
        
    def nome_instituicoes(self):
        """
        Consulta nome das Instituições.
        :return:
        retorna uma lista zipada de nomes de Instituições sem prepetição.
        """
        cursor = self.cursor()
        cursor.execute('SELECT DISTINCT (nome_inst) FROM resultados')
        self.nome_inst = cursor.fetchall()
        return self.nome_inst


    def cod_instituicao(self):
        """
        consulta códigos das instituições
        :return:
        retorna a consulta de códigos das instituições sem repetição
        """
        cursor = self.cursor()
        cursor.execute('SELECT DISTINCT(cod_inst) from resultados')
        codigoInst = cursor.fetchall()
        for data in codigoInst:
            self.codigo_instituicao.append(data)
        return self.codigo_instituicao


    def cod_nome_instituicao(self):
        '''
        retorna a consulta de nome e código das instituições sem repetição
        '''
        cursor = self.cursor()
        cursor.execute('SELECT DISTINCT(cod_inst), nome_inst FROM resultados')
        self.geral_code = cursor.fetchall()
        cursor.execute('SELECT DISTINCT(cod_inst), nome_inst FROM resultados')
        self.geral_code = cursor.fetchall()
        return self.geral_code

    def nome_distrito(self):
        """
        consulta nome dos distritos
        :return:
        retorna uma lista zipada com nome dos distritod
        """
        cursor = self.cursor()
        cursor.execute('SELECT DISTINCT (distrito) FROM resultados')
        data = cursor.fetchall()
        for i in (data):
            self.nome_distritos.append(i[0])
        return self.nome_distritos


    def colocados_instituicao(self):
        """
        Consulta a soma de colocados por nome de Instituição.
        :return:
        retorna uma lista com a soma de colocados por Instituição.
        """
        cursor = self.cursor()
        cursor.execute('SELECT nome_inst, SUM(colocados) FROM resultados GROUP BY nome_inst')
        data = cursor.fetchall()
        for i in (data):
            self.colocados_p_inst.append(i)
        return self.colocados_p_inst


    def colocados_distrito(self):
        """
        Consulta o número de alunos colocados por Distrito.
        :return:
        retorna duas listas uma com nome dos Distritos e outra
        com a soma de colocados.
        """
        cursor = self.cursor()
        cursor.execute('SELECT distrito, SUM(colocados) FROM resultados GROUP BY distrito')
        data = cursor.fetchall()
        print data
        for i in (data):
            self.colocados_p_dist.append(i)
            self.colocados_p_dist1.append(i[1])


    def vagas_instituicao(self):
        """
        Consulta o número de vagas restantes por Instituição.
        :return:
        Retorna uma lista uma com nome das Instituições e
        com o número de vagas que sobraram.
        """
        cursor = self.cursor()
        cursor.execute('SELECT nome_inst, SUM(vagas_fim) FROM resultados GROUP BY nome_inst')
        data = cursor.fetchall()
        for i in (data):
            self.vagas_p_inst.append(i)


    def vagas_distrito(self):
        """
        Consulta o número de vagas restantes por Distrito.
        :return:
        retorna duas listas uma com nome dos Distritos e outra
        com o número de vagas que sobraram.
        """
        cursor = self.cursor()
        cursor.execute('SELECT distrito, SUM(vagas_fim) FROM resultados GROUP BY distrito')
        data = cursor.fetchall()
        for i in (data):
            self.vagas_p_dist.append(i)


    def vagas_total(self):
        """
        Consulta o número de vagas iniciais por Distrito.
        :return:
        retorna duas listas uma com nome dos Distritos e outra
        com o número de vagas iniciais.
        """
        cursor = self.cursor()
        cursor.execute('SELECT distrito, SUM(vagas_init) FROM resultados GROUP BY distrito')
        data = cursor.fetchall()
        for i in (data):
            self.vagas_p_dist_init.append(i[1])


    def porcem(self, total_alunos, qtd_alunos_colocados):
        """
        determinação da percentagem (razão por 1000)
        total_alunos - total de alunos colocados, tipo float
        qtd_alunos_colocados - quantidade de alunos colocados por
        distrito
        """
        return (qtd_alunos_colocados / float(total_alunos)) * 100.0


    def pormil(self, total_alunos, qtd_alunos_distrito):
        """
        determinação da permilagem (razão por 1000)
        total_alunos - total de alunos, tipo float
        qtd_alunos_distrito - quantidade de alunos colocados por
        distrito
        """
        return (qtd_alunos_distrito / float(total_alunos)) * 1000.0


    def porcentagem_valor(self):
        '''
        Porcentagem de colocados por instituição em relação a todos os
        colocados
        '''
        cursor = self.cursor()
        cursor.execute('SELECT SUM(colocados) FROM resultados')
        data = cursor.fetchone()
        for i in (self.colocados_p_inst):
            self.porcentagem.append(self.porcem(data[0], i[1]))
            self.nome_institui.append(i[0])
        self.porcentagem_valor_zip = zip(self.nome_institui, self.porcentagem)


    def pormilagem_valor(self):
        '''
        Permilagem de colocados por distrito
        '''
        cursor = self.cursor()
        cursor.execute('SELECT SUM(colocados) FROM resultados')
        data = cursor.fetchone()
        for i in (self.colocados_p_dist):
            self.permilagem.append(self.pormil(data[0], i[1]))
            self.nome_institui.append(i[0])
        self.pormilagem_valor_zip = zip(self.nome_institui, self.permilagem)


    nomedistrito = ''

    def colocados_nome_distrito(self, nome_dist):
        '''
        Função que recebe o nome do distrito e gera o filtro com todas
        as instituições referentes
        nome_dist - Nome do distrito solicitado
        '''

        cursor = self.cursor()
        cursor.execute(
            'SELECT nome_inst, sum(colocados) from resultados WHERE distrito="%s" group by distrito, nome_inst' % nome_dist)
        data = cursor.fetchall()
        self.nomedistrito = nome_dist
        for i in (data):
            self.colocados_dist.append(i[1])
            self.nome_instituicao.append(i[0])

    # Exporta a base de dados para um ficheiro .CSV;
    def exportar_ficheiro(self):
        """
        Faz a exportação das estatisticas para ficheiros com o
        nome referente a consulta.
        """

        self.colocados_instituicao()
        self.colocados_distrito()
        self.porcentagem_valor()
        self.pormilagem_valor()
        self.vagas_distrito()
        self.vagas_instituicao()

        ExportFile.exportar_ficheiro('colocadosInstituicao', self.colocados_p_inst)
        ExportFile.exportar_ficheiro('colocadosDistrito', self.colocados_p_dist)
        ExportFile.exportar_ficheiro('porcentagemAlunos', self.porcentagem_valor_zip)
        ExportFile.exportar_ficheiro('permilagemAlunos', self.pormilagem_valor_zip)
        ExportFile.exportar_ficheiro('vagasInstituicao', self.vagas_p_inst)
        ExportFile.exportar_ficheiro('vagasDistrito', self.vagas_p_dist)

    ################## GRAFICOS ############################################
    def graf(self, graf1, titulo, legenda1, legenda_yy, legenda_xx):
        '''
        Função que desenha um gráfico
        graf1 - lista com valores a atribuir ao grafico
        titulo - titulo do grafico
        legenda1 - legenda correspondente ao grafico
        legenda_yy - legenda do eixo dos yy
        legenda_xx - legenda do eixo dos xx
        ------------
        n - numero de barras do gráfico, tipo int
        ind = localização das barras
        width - tamanho das barras, tipo float
        '''
        N = len(graf1)
        ind = np.arange(N) + 1.5
        width = 0.35
        fig = plt.figure()
        ax = fig.add_subplot(111)
        yvals = graf1
        rects1 = ax.bar(ind, yvals, width, color='#462125')
        ax.legend((rects1[0], ), (legenda1, ))
        ax.set_title(titulo, fontstyle='italic')
        ax.set_ylabel(legenda_yy)
        ax.set_xticks(ind + width)
        ax.set_xticklabels(legenda_xx, rotation=90)
        plt.show()


    def grafs(self, graf1, graf2, titulo, legenda1, legenda2, legenda_yy, legenda_xx):
        '''
        Função que desenha dois gráficos na mesma janela permitindo a
        comparação
        graf1 - lista com valores a atribuir ao grafico 1
        graf2 - lista com valores a atribuir ao grafico 2
        titulo - titulo do grafico
        legenda1 - legenda correspondente ao grafico 1
        legenda2 - legenda correspondente ao grafico 2
        legenda_yy - legenda do eixo dos yy
        legenda_xx - legenda do eixo dos xx
        ------------
        n - numero de barras do gráfico, tipo int
        ind = localização das barras
        width - tamanho das barras, tipo float
        '''
        N = len(graf1)
        ind = np.arange(N) + 1.5
        width = 0.35
        fig = plt.figure()
        ax = fig.add_subplot(111)
        yvals = graf1
        zvals = graf2
        rects1 = ax.bar(ind, yvals, width, color='#462125')
        rects2 = ax.bar(ind + width, zvals, width, color='#886433')
        ax.legend((rects1[0], rects2[0]), (legenda1, legenda2))
        ax.set_title(titulo, fontstyle='italic')
        ax.set_ylabel(legenda_yy)
        ax.set_xticks(ind + width)
        ax.set_xticklabels(legenda_xx, rotation=90)
        plt.show()


        ############################################################
        # def label(rects):
        #     '''
        #     Coloca os valores dos gráficos sobre as colunas
        #     rects - gráfico a receber valores
        #     '''
        #     for rect in rects:
        #         h = rect.get_height()
        #         ax.text(rect.get_x()+rect.get_width()/2., 1.05*h, '%d'%int(h), ha='center', va='bottom')

    def leituraGraficos(self):
        """
        Chama as funções para geração dos gráficos referentes as
        estatisticas
        """
        self.porcentagem_valor()
        self.pormilagem_valor()
        self.nome_distrito()
        self.vagas_total()
        self.colocados_distrito
        self.limpa_lista()

